#include "BleServerConnector.h"
#include "BleManager.h"
#include "common.h"

bool BleServerConnector::isEmpty() {
    return _isEmpty;
}

void BleServerConnector::destory() {
    if (_isEmpty) {
        return;
    }
    clear();
    _isEmpty = true;
}

void BleServerConnector::clear() {

    if (_BLEClient != nullptr) {
        _BLEClient->disconnect();
        _BLEClient = nullptr;
    }
    _pReadReportCharacteristic = nullptr;
    _pWriteReportCharacteristic = nullptr;
    if (_pCallbacks) {
        _pCallbacks->ble_onDisconnect(this);
    }
    _status = 0;
}

std::string BleServerConnector::readValue() {

    if (_pReadReportCharacteristic != NULL) {
        return _pReadReportCharacteristic->readValue();
    }
    return "";
}

void BleServerConnector::connectToServer() {

    if (_status == 0) {
        // 发现设备 --> 尝试连接
        // 配置安全参数
        NimBLEDevice::setSecurityAuth(BLE_SM_PAIR_AUTHREQ_SC);

        // 创建客户端实例
        if (_BLEClient == nullptr) {
            _BLEClient = BLEDevice::createClient();
            _BLEClient->setClientCallbacks(this);
        }

        // 连接BLE server
        // Serial.println("连接 BLE server");
        BLEAddress bleAddress(_address, _addressType);
        _BLEClient->setConnectTimeout(500);
        bool bRes = _BLEClient->connect(bleAddress);
        if (!bRes) {
            return; // connect 失败
        }
        Serial.println("connect 成功");
        return;
    }

    if (_status == 2) {
        // 已配对 --> 尝试识别HID设备

        if (_cntFail++ > 3) {
            // 获取HID设备信息失败，断开连接。用户可以删除后重新配对
            _BLEClient->disconnect();
            _status = -1;
            return;
        }

        // 在服务端寻找HID服务——假设该设备只有一个HID
        BLERemoteService *pRemoteService = _BLEClient->getService(BLE_SERVER_SERVICE_UUID_HID);
        if (pRemoteService == nullptr) {
            // 没有找到目标服务的SERVICE_UUID
            return;
        }

        bool flag = true;
        // 分析HID报表描述符
        _pCallbacks->ble_onConnect(this, pRemoteService, flag);

        if (flag) {

            // 查找报表的特征
            const std::vector<NimBLERemoteCharacteristic *> &chars = pRemoteService->getCharacteristics(true);

            // 查找输入和输出报告
            for (auto pChar : chars) {
                if (pChar->getUUID() == NimBLEUUID("2A4D")) {
                    if (pChar->canNotify()) {
                        _pReadReportCharacteristic = pChar;
                        _pCallbacks->ble_bindReadReportCharacteristic(this, _pReadReportCharacteristic);
                        _pReadReportCharacteristic->subscribe(true, BleManager::onRecvData, true);
                    } else if (pChar->canWrite()) {
                        _pWriteReportCharacteristic = pChar;
                    }
                    _status = 3; // 已识别HID
                }
            }
        }
    }
    return;
}

void BleServerConnector::onConnect(NimBLEClient *pClient) {
    Serial.printf("Connected\n");
    _status = 1; // 已连接

    // 请求配对/加密
    pClient->secureConnection();
}

void BleServerConnector::onDisconnect(NimBLEClient *pClient, int reason) {
    Serial.printf("onDisconnect: %s, reason = %d\n", pClient->getPeerAddress().toString().c_str(), reason);
    // reason的定义在：NimBLE-Arduino/src/nimble/nimble/host/include/host/ble_hs.h
    _status = 0;
    _pCallbacks->ble_onDisconnect(this);
    clear();
}

void BleServerConnector::onPassKeyEntry(NimBLEConnInfo &connInfo) {
    Serial.printf("Server Passkey Entry\n");
    NimBLEDevice::injectPassKey(connInfo, 0);
}

void BleServerConnector::onConfirmPasskey(NimBLEConnInfo &connInfo, uint32_t pass_key) {
    Serial.printf("The passkey YES/NO number: %d\n", pass_key);
    /** Inject false if passkeys don't match. */
    NimBLEDevice::injectConfirmPasskey(connInfo, true);
}

// 认证成功或失败后调用
void BleServerConnector::onAuthenticationComplete(NimBLEConnInfo &connInfo) {
    _ConnTimeout = connInfo.getConnTimeout() * 10;
    Serial.printf("onAuthenticationComplete. ConnTimeout: %d(ms)\n", _ConnTimeout);

    if (connInfo.isEncrypted()) {
        _status = 2;
        _cntFail = 0;
        Serial.println("Pairing success");
    } else {
        // 配对失败，断开连接。用户可以删除后重新配对
        _BLEClient->disconnect();
        _status = -1;
        Serial.println("Pairing failed");
    }
}

void BleServerConnector::setBleServerConnectorCallbacks(BleServerConnectorCallbacks *pCallbacks) {
    _pCallbacks = pCallbacks;
}

void BleServerConnector::setOnRecvData(setOnRecvData_t cb) {
    onRecvData = cb;
}

void BleServerConnector::recvData(uint8_t *dataBuf, int nLen, bool isNotify) {
    onRecvData(this, dataBuf, nLen);
}

void BleServerConnector::setLED(uint8_t flags) {
    if (!_pWriteReportCharacteristic) {
        return;
    }

    // TODO 未完成蓝牙键盘的LED设置
}